package br.ufmg.ubicomp.droidguide.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sun.net.ssl.HttpsURLConnection;

/**
 * utility class responsible for handling URL requests to the server and 
 * receive the response.
 * @author wpjr
 *
 */
public class RequestUtil {

	private static final String CLASS_NAME = "RequestUtil.executeUrl";

	public static String executeUrl(String url) throws IOException {
		String result = null;
			URL droidGuideServer = new URL(url);
			
			URLConnection yc = droidGuideServer.openConnection();
			BufferedReader in = new BufferedReader(
					new InputStreamReader(
							yc.getInputStream()));
			String inputLine;
			StringBuilder sb = new StringBuilder();
			while ((inputLine = in.readLine()) != null)
			{
				//System.out.println(inputLine);
				sb.append(inputLine);
			}
			in.close();	
			result = sb.toString();
			Logger logger = Logger.getLogger(CLASS_NAME);
			logger.info("Read " + result.length() + " bytes from " + url);
			//showLogInfo(yc);
		return result;
	}

	public static NodeList executeUrlDOM(String url) throws IOException, Exception {
		String result = null;
			Logger logger = Logger.getLogger(CLASS_NAME);
			URL droidGuideServer = new URL(url);
			logger.info(url);
			URLConnection yc = droidGuideServer.openConnection();
			BufferedReader in = new BufferedReader(
					new InputStreamReader(
							yc.getInputStream()));
			String inputLine;
			StringBuilder sb = new StringBuilder();
			while ((inputLine = in.readLine()) != null)
			{
				//System.out.println(inputLine);
				sb.append(inputLine);
			}
			in.close();	
			result = sb.toString();
			System.out.println(result);
			ByteArrayInputStream bais = new ByteArrayInputStream(result.getBytes());
			/* Parse XML */
			DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			Document doc = docBuilder.parse(bais);
			// root element.
			Element root = doc.getDocumentElement();
			// Entities
			if (root == null)
			{
				logger.info("RequestUtil: root is null!");			
			}
			NodeList entities = root.getChildNodes();
			return entities;			
	}

	public static NodeList executeUrlDomPOST(String url, Map<String, String> params) throws IOException, Exception {
		
		Logger logger = Logger.getLogger(CLASS_NAME);
		
		HttpURLConnection yc = sendPost(url, params, logger);			
		NodeList entities = readResponse(logger, yc);
		return entities;			
	}

	private static NodeList readResponse(Logger logger, HttpURLConnection yc)
			throws IOException, ParserConfigurationException, SAXException {
		String result;
		BufferedReader in = new BufferedReader(
				new InputStreamReader(
						yc.getInputStream()));
		String inputLine;
		StringBuilder sb = new StringBuilder();
		while ((inputLine = in.readLine()) != null)
		{
			//System.out.println(inputLine);
			sb.append(inputLine);
		}
		in.close();	
		result = sb.toString();

		ByteArrayInputStream bais = new ByteArrayInputStream(result.getBytes());
		/* Parse XML */
		DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder();
		Document doc = docBuilder.parse(bais);
		// root element.
		Element root = doc.getDocumentElement();
		// Entities
		if (root == null)
		{
			logger.info("RequestUtil: root is null!");			
		}
		NodeList entities = root.getChildNodes();
		return entities;
	}

	private static HttpURLConnection sendPost(String url,
			Map<String, String> params, Logger logger)
			throws MalformedURLException, IOException, ProtocolException,
			UnsupportedEncodingException {
		URL droidGuideServer = new URL(url);			
		logger.info(url);
		
		HttpURLConnection yc = (HttpURLConnection) droidGuideServer.openConnection();
		yc.setRequestMethod("POST");
		yc.setDoOutput(true);
		yc.setDoInput(true);
		yc.setUseCaches(false);
		yc.setAllowUserInteraction(false);
		
		StringBuilder sb = new StringBuilder();
		for (String s: params.keySet())
		{
			sb.append(URLEncoder.encode(s, "UTF-8")).append("=").append(URLEncoder.encode(params.get(s), "UTF-8")).append("&");
		}
		// removing the & character
		sb.deleteCharAt(sb.length() - 1);			
		OutputStreamWriter writer = new OutputStreamWriter(yc.getOutputStream());
		writer.write(sb.toString());
		writer.flush();
		writer.close();
		return yc;
	}

	private static void showLogInfo(URLConnection yc) {
		Logger logger = Logger.getLogger(CLASS_NAME);
		logger.setLevel(Level.FINE);
		logger.log(Level.INFO, "Content encoding: " + yc.getContentEncoding());
		logger.log(Level.INFO, "Content length: " + yc.getContentLength());
		logger.log(Level.INFO, "Content type: " + yc.getContentType());
		logger.log(Level.INFO, "Date: " + new Date(yc.getDate()));
		logger.log(Level.INFO, "Request Properties: ");
		Map<String, List<String>> reqProps = yc.getHeaderFields();
		for (String key: reqProps.keySet())
		{
			logger.log(Level.INFO, "Key: " + key + "= " +
					reqProps.get(key));
		}
	}
	
	
}
